//===--- Frontend.h - frontend utility methods ------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file contains declarations of utility methods for parsing and
// performing semantic on modules.
//
//===----------------------------------------------------------------------===//

#ifndef POLARPHP_FRONTEND_FRONTEND_H
#define POLARPHP_FRONTEND_FRONTEND_H

#include "polarphp/ast/DiagnosticConsumer.h"
#include "polarphp/ast/DiagnosticEngine.h"
#include "polarphp/ast/IRGenOptions.h"
#include "polarphp/ast/LinkLibrary.h"
#include "polarphp/ast/Module.h"
#include "polarphp/ast/PILOptions.h"
#include "polarphp/ast/SearchPathOptions.h"
#include "polarphp/ast/SourceFile.h"
#include "polarphp/basic/DiagnosticOptions.h"
#include "polarphp/kernel/LangOptions.h"
#include "polarphp/basic/SourceMgr.h"
#include "polarphp/clangimporter/ClangImporter.h"
#include "polarphp/clangimporter/ClangImporterOptions.h"
#include "polarphp/frontend/FrontendOptions.h"
#include "polarphp/frontend/ModuleInterfaceSupport.h"
//#include "polarphp/migrator/MigratorOptions.h"
#include "polarphp/llparser/CodeCompletionCallbacks.h"
#include "polarphp/llparser/Parser.h"
#include "polarphp/sema/SourceLoader.h"
#include "polarphp/serialization/Validation.h"
#include "polarphp/global/Subsystems.h"
#include "polarphp/tbdgen/TBDGen.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "clang/Basic/FileManager.h"

#include <memory>

namespace polar {

class SerializedModuleLoader;
class MemoryBufferSerializedModuleLoader;
class PILModule;

namespace lowering {
class TypeConverter;
}

struct ModuleBuffers {
   std::unique_ptr<llvm::MemoryBuffer> ModuleBuffer;
   std::unique_ptr<llvm::MemoryBuffer> ModuleDocBuffer;
   std::unique_ptr<llvm::MemoryBuffer> ModuleSourceInfoBuffer;
   ModuleBuffers(std::unique_ptr<llvm::MemoryBuffer> ModuleBuffer,
                 std::unique_ptr<llvm::MemoryBuffer> ModuleDocBuffer = nullptr,
                 std::unique_ptr<llvm::MemoryBuffer> ModuleSourceInfoBuffer = nullptr):
      ModuleBuffer(std::move(ModuleBuffer)),
      ModuleDocBuffer(std::move(ModuleDocBuffer)),
      ModuleSourceInfoBuffer(std::move(ModuleSourceInfoBuffer)) {}
};

/// The abstract configuration of the compiler, including:
///   - options for all stages of translation,
///   - information about the build environment,
///   - information about the job being performed, and
///   - lists of inputs and outputs.
///
/// A CompilerInvocation can be built from a frontend command line
/// using parseArgs.  It can then be used to build a CompilerInstance,
/// which manages the actual compiler execution.
class CompilerInvocation {
   LangOptions LangOpts;
   TypeCheckerOptions TypeCheckerOpts;
   FrontendOptions FrontendOpts;
   ClangImporterOptions ClangImporterOpts;
   SearchPathOptions SearchPathOpts;
   DiagnosticOptions DiagnosticOpts;
//   MigratorOptions MigratorOpts;
   PILOptions PILOpts;
   IRGenOptions IRGenOpts;
   TBDGenOptions TBDGenOpts;
   ModuleInterfaceOptions ModuleInterfaceOpts;
   /// The \c SyntaxParsingCache to use when parsing the main file of this
   /// invocation
   SyntaxParsingCache *MainFileSyntaxParsingCache = nullptr;

   llvm::MemoryBuffer *CodeCompletionBuffer = nullptr;

   /// Code completion offset in bytes from the beginning of the main
   /// source file.  Valid only if \c isCodeCompletion() == true.
   unsigned CodeCompletionOffset = ~0U;

   CodeCompletionCallbacksFactory *CodeCompletionFactory = nullptr;

public:
   CompilerInvocation();

   /// Initializes the compiler invocation for the list of arguments.
   ///
   /// All parsing should be additive, i.e. options should not be reset to their
   /// default values given the /absence/ of a flag. This is because \c parseArgs
   /// may be used to modify an already partially configured invocation.
   ///
   /// Any configuration files loaded as a result of parsing arguments will be
   /// stored in \p ConfigurationFileBuffers, if non-null. The contents of these
   /// buffers should \e not be interpreted by the caller; they are only present
   /// in order to make it possible to reproduce how these arguments were parsed
   /// if the compiler ends up crashing or exhibiting other bad behavior.
   ///
   /// If non-empty, relative search paths are resolved relative to
   /// \p workingDirectory.
   ///
   /// \returns true if there was an error, false on success.
   bool parseArgs(ArrayRef<const char *> Args, DiagnosticEngine &Diags,
                  SmallVectorImpl<std::unique_ptr<llvm::MemoryBuffer>>
                  *ConfigurationFileBuffers = nullptr,
                  StringRef workingDirectory = {});

   /// Sets specific options based on the given serialized Swift binary data.
   ///
   /// This is additive, i.e. options are not reset to their default values given
   /// the /absence/ of a flag. However, flags that only have a single value may
   /// (and should) be overwritten by this method.
   ///
   /// Invoking this on more than one serialized AST is likely to result in
   /// one or both of them failing to load. Please pick one AST to provide base
   /// flags for the entire AstContext and let the others succeed or fail the
   /// normal way. (Some additive flags, like search paths, will be handled
   /// properly during normal module loading.)
   ///
   /// \returns Status::Valid on success, one of the Status issues on error.
   serialization::Status loadFromSerializedAST(StringRef data);

   /// Serialize the command line arguments for emitting them
   /// to DWARF or CodeView and inject SDKPath if necessary.
   static void buildDebugFlags(std::string &Output,
                               const ArrayRef<const char*> &Args,
                               StringRef SDKPath,
                               StringRef ResourceDir);

   void setTargetTriple(const llvm::Triple &Triple);
   void setTargetTriple(StringRef Triple);

   StringRef getTargetTriple() const {
      return LangOpts.Target.str();
   }

   void setClangModuleCachePath(StringRef Path) {
      ClangImporterOpts.ModuleCachePath = Path.str();
   }

   StringRef getClangModuleCachePath() const {
      return ClangImporterOpts.ModuleCachePath;
   }

   void setImportSearchPaths(const std::vector<std::string> &Paths) {
      SearchPathOpts.ImportSearchPaths = Paths;
   }

   ArrayRef<std::string> getImportSearchPaths() const {
      return SearchPathOpts.ImportSearchPaths;
   }

   void setFrameworkSearchPaths(
      const std::vector<SearchPathOptions::FrameworkSearchPath> &Paths) {
      SearchPathOpts.FrameworkSearchPaths = Paths;
   }

   ArrayRef<SearchPathOptions::FrameworkSearchPath> getFrameworkSearchPaths() const {
      return SearchPathOpts.FrameworkSearchPaths;
   }

   void setExtraClangArgs(const std::vector<std::string> &Args) {
      ClangImporterOpts.ExtraArgs = Args;
   }

   ArrayRef<std::string> getExtraClangArgs() const {
      return ClangImporterOpts.ExtraArgs;
   }

   void addLinkLibrary(StringRef name, LibraryKind kind) {
      IRGenOpts.LinkLibraries.push_back({name, kind});
   }

   ArrayRef<LinkLibrary> getLinkLibraries() const {
      return IRGenOpts.LinkLibraries;
   }

   void setMainExecutablePath(StringRef Path);

   void setRuntimeResourcePath(StringRef Path);

   /// Computes the runtime resource path relative to the given Swift
   /// executable.
   static void computeRuntimeResourcePathFromExecutablePath(
      StringRef mainExecutablePath,
      llvm::SmallString<128> &runtimeResourcePath);

   void setSDKPath(const std::string &Path);

   StringRef getSDKPath() const {
      return SearchPathOpts.SDKPath;
   }

   LangOptions &getLangOptions() {
      return LangOpts;
   }
   const LangOptions &getLangOptions() const {
      return LangOpts;
   }

   TypeCheckerOptions &getTypeCheckerOptions() { return TypeCheckerOpts; }
   const TypeCheckerOptions &getTypeCheckerOptions() const {
      return TypeCheckerOpts;
   }

   FrontendOptions &getFrontendOptions() { return FrontendOpts; }
   const FrontendOptions &getFrontendOptions() const { return FrontendOpts; }

   TBDGenOptions &getTBDGenOptions() { return TBDGenOpts; }
   const TBDGenOptions &getTBDGenOptions() const { return TBDGenOpts; }

   ModuleInterfaceOptions &getModuleInterfaceOptions() { return ModuleInterfaceOpts; }
   const ModuleInterfaceOptions &getModuleInterfaceOptions() const { return ModuleInterfaceOpts; }

   ClangImporterOptions &getClangImporterOptions() { return ClangImporterOpts; }
   const ClangImporterOptions &getClangImporterOptions() const {
      return ClangImporterOpts;
   }

   SearchPathOptions &getSearchPathOptions() { return SearchPathOpts; }
   const SearchPathOptions &getSearchPathOptions() const {
      return SearchPathOpts;
   }

   DiagnosticOptions &getDiagnosticOptions() { return DiagnosticOpts; }
   const DiagnosticOptions &getDiagnosticOptions() const {
      return DiagnosticOpts;
   }

//   const MigratorOptions &getMigratorOptions() const {
//      return MigratorOpts;
//   }

   PILOptions &getPILOptions() { return PILOpts; }
   const PILOptions &getPILOptions() const { return PILOpts; }

   IRGenOptions &getIRGenOptions() { return IRGenOpts; }
   const IRGenOptions &getIRGenOptions() const { return IRGenOpts; }

   void setMainFileSyntaxParsingCache(SyntaxParsingCache *Cache) {
      MainFileSyntaxParsingCache = Cache;
   }

   SyntaxParsingCache *getMainFileSyntaxParsingCache() const {
      return MainFileSyntaxParsingCache;
   }

   void setParseStdlib() {
      FrontendOpts.ParseStdlib = true;
   }

   bool getParseStdlib() const {
      return FrontendOpts.ParseStdlib;
   }

   void setInputKind(InputFileKind K) {
      FrontendOpts.InputKind = K;
   }

   InputFileKind getInputKind() const {
      return FrontendOpts.InputKind;
   }

   SourceFileKind getSourceFileKind() const;

   void setModuleName(StringRef Name) {
      FrontendOpts.ModuleName = Name.str();
      IRGenOpts.ModuleName = Name.str();
   }

   StringRef getModuleName() const {
      return FrontendOpts.ModuleName;
   }

   std::string getOutputFilename() const {
      return FrontendOpts.InputsAndOutputs.getSingleOutputFilename();
   }

   void setCodeCompletionPoint(llvm::MemoryBuffer *Buf, unsigned Offset) {
      assert(Buf);
      CodeCompletionBuffer = Buf;
      CodeCompletionOffset = Offset;
      // We don't need typo-correction for code-completion.
      // FIXME: This isn't really true, but is a performance issue.
      LangOpts.TypoCorrectionLimit = 0;
   }

   std::pair<llvm::MemoryBuffer *, unsigned> getCodeCompletionPoint() const {
      return std::make_pair(CodeCompletionBuffer, CodeCompletionOffset);
   }

   /// \returns true if we are doing code completion.
   bool isCodeCompletion() const {
      return CodeCompletionOffset != ~0U;
   }

   void setCodeCompletionFactory(CodeCompletionCallbacksFactory *Factory) {
      CodeCompletionFactory = Factory;
      disableAstScopeLookup();
   }

   /// Called from lldb, see rdar://53971116
   void disableAstScopeLookup() {
      LangOpts.EnableAstScopeLookup = false;
   }

   CodeCompletionCallbacksFactory *getCodeCompletionFactory() const {
      return CodeCompletionFactory;
   }

   /// Retrieve a module hash string that is suitable for uniquely
   /// identifying the conditions under which the module was built, for use
   /// in generating a cached PCH file for the bridging header.
   std::string getPCHHash() const;

   SourceFile::ImplicitModuleImportKind getImplicitModuleImportKind() {
      if (getInputKind() == InputFileKind::PIL) {
         return SourceFile::ImplicitModuleImportKind::None;
      }
      if (getParseStdlib()) {
         return SourceFile::ImplicitModuleImportKind::Builtin;
      }
      return SourceFile::ImplicitModuleImportKind::Stdlib;
   }

   /// Performs input setup common to these tools:
   /// sil-opt, sil-func-extractor, sil-llvm-gen, and sil-nm.
   /// Return value includes the buffer so caller can keep it alive.
   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
   setUpInputForPILTool(StringRef inputFilename, StringRef moduleNameArg,
                        bool alwaysSetModuleToMain, bool bePrimary,
                        serialization::ExtendedValidationInfo &extendedInfo);
   bool hasSerializedAST() {
      return FrontendOpts.InputKind == InputFileKind::PHPLibrary;
   }

   const PrimarySpecificPaths &
   getPrimarySpecificPathsForAtMostOnePrimary() const;
   const PrimarySpecificPaths &
   getPrimarySpecificPathsForPrimary(StringRef filename) const;
   const PrimarySpecificPaths &
   getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const;

   std::string getOutputFilenameForAtMostOnePrimary() const;
   std::string getMainInputFilenameForDebugInfoForAtMostOnePrimary() const;
   std::string getObjCHeaderOutputPathForAtMostOnePrimary() const;
   std::string getModuleOutputPathForAtMostOnePrimary() const;
   std::string
   getReferenceDependenciesFilePathForPrimary(StringRef filename) const;
   std::string getSwiftRangesFilePathForPrimary(StringRef filename) const;
   std::string getCompiledSourceFilePathForPrimary(StringRef filename) const;
   std::string getSerializedDiagnosticsPathForAtMostOnePrimary() const;

   /// TBDPath only makes sense in whole module compilation mode,
   /// so return the TBDPath when in that mode and fail an assert
   /// if not in that mode.
   std::string getTBDPathForWholeModule() const;

   /// ModuleInterfaceOutputPath only makes sense in whole module compilation
   /// mode, so return the ModuleInterfaceOutputPath when in that mode and
   /// fail an assert if not in that mode.
   std::string getModuleInterfaceOutputPathForWholeModule() const;

   SerializationOptions
   computeSerializationOptions(const SupplementaryOutputPaths &outs,
                               bool moduleIsPublic);
};

/// A class which manages the state and execution of the compiler.
/// This owns the primary compiler singletons, such as the AstContext,
/// as well as various build products such as the PILModule.
///
/// Before a CompilerInstance can be used, it must be configured by
/// calling \a setup.  If successful, this will create an AstContext
/// and set up the basic compiler invariants.  Calling \a setup multiple
/// times on a single CompilerInstance is not permitted.
class CompilerInstance {
   CompilerInvocation Invocation;
   SourceManager SourceMgr;
   DiagnosticEngine Diagnostics{SourceMgr};
   std::unique_ptr<AstContext> Context;
   std::unique_ptr<lowering::TypeConverter> ThePILTypes;
   std::unique_ptr<PILModule> ThePILModule;

   std::unique_ptr<PersistentParserState> PersistentState;

   /// Null if no tracker.
   std::unique_ptr<DependencyTracker> DepTracker;

   ModuleDecl *MainModule = nullptr;
   SerializedModuleLoader *SML = nullptr;
   MemoryBufferSerializedModuleLoader *MemoryBufferLoader = nullptr;

   /// Contains buffer IDs for input source code files.
   std::vector<unsigned> InputSourceCodeBufferIDs;

   /// Contains \c MemoryBuffers for partial serialized module files and
   /// corresponding partial serialized module documentation files.
   std::vector<ModuleBuffers> PartialModules;

   enum : unsigned { NO_SUCH_BUFFER = ~0U };
   unsigned MainBufferID = NO_SUCH_BUFFER;

   /// Identifies the set of input buffers in the SourceManager that are
   /// considered primaries.
   llvm::SetVector<unsigned> PrimaryBufferIDs;

   /// Identifies the set of SourceFiles that are considered primaries. An
   /// invariant is that any SourceFile in this set with an associated
   /// buffer will also have its buffer ID in PrimaryBufferIDs.
   std::vector<SourceFile *> PrimarySourceFiles;

   /// Return whether there is an entry in PrimaryInputs for buffer \p BufID.
   bool isPrimaryInput(unsigned BufID) const {
      return PrimaryBufferIDs.count(BufID) != 0;
   }

   /// Record in PrimaryBufferIDs the fact that \p BufID is a primary.
   /// If \p BufID is already in the set, do nothing.
   void recordPrimaryInputBuffer(unsigned BufID);

   /// Record in PrimarySourceFiles the fact that \p SF is a primary, and
   /// call recordPrimaryInputBuffer on \p SF's buffer (if it exists).
   void recordPrimarySourceFile(SourceFile *SF);

   bool isWholeModuleCompilation() { return PrimaryBufferIDs.empty(); }

public:
   // Out of line to avoid having to import PILModule.h.
   CompilerInstance();
   ~CompilerInstance();

   CompilerInstance(const CompilerInstance &) = delete;
   void operator=(const CompilerInstance &) = delete;
   CompilerInstance(CompilerInstance &&) = delete;
   void operator=(CompilerInstance &&) = delete;

   SourceManager &getSourceMgr() { return SourceMgr; }

   DiagnosticEngine &getDiags() { return Diagnostics; }

   llvm::vfs::FileSystem &getFileSystem() { return *SourceMgr.getFileSystem(); }

   AstContext &getAstContext() {
      return *Context;
   }
   bool hasAstContext() const { return Context != nullptr; }

   PILOptions &getPILOptions() { return Invocation.getPILOptions(); }
   const PILOptions &getPILOptions() const { return Invocation.getPILOptions(); }

   lowering::TypeConverter &getPILTypes();

   void createPILModule();

   void addDiagnosticConsumer(DiagnosticConsumer *DC) {
      Diagnostics.addConsumer(*DC);
   }

   void createDependencyTracker(bool TrackSystemDeps) {
      assert(!Context && "must be called before setup()");
      DepTracker = std::make_unique<DependencyTracker>(TrackSystemDeps);
   }
   DependencyTracker *getDependencyTracker() { return DepTracker.get(); }

   /// Set the PIL module for this compilation instance.
   ///
   /// The CompilerInstance takes ownership of the given PILModule object.
   void setPILModule(std::unique_ptr<PILModule> M);

   PILModule *getPILModule() {
      return ThePILModule.get();
   }

   std::unique_ptr<PILModule> takePILModule();

   bool hasPILModule() {
      return static_cast<bool>(ThePILModule);
   }

   ModuleDecl *getMainModule();

   MemoryBufferSerializedModuleLoader *
   getMemoryBufferSerializedModuleLoader() const {
      return MemoryBufferLoader;
   }

   ArrayRef<unsigned> getInputBufferIDs() const {
      return InputSourceCodeBufferIDs;
   }

   ArrayRef<LinkLibrary> getLinkLibraries() const {
      return Invocation.getLinkLibraries();
   }

   bool hasSourceImport() const {
      return Invocation.getFrontendOptions().EnableSourceImport;
   }

   /// Gets the set of SourceFiles which are the primary inputs for this
   /// CompilerInstance.
   ArrayRef<SourceFile *> getPrimarySourceFiles() {
      return PrimarySourceFiles;
   }

   /// Gets the SourceFile which is the primary input for this CompilerInstance.
   /// \returns the primary SourceFile, or nullptr if there is no primary input;
   /// if there are _multiple_ primary inputs, fails with an assertion.
   ///
   /// FIXME: This should be removed eventually, once there are no longer any
   /// codepaths that rely on a single primary file.
   SourceFile *getPrimarySourceFile() {
      if (PrimarySourceFiles.empty()) {
         return nullptr;
      } else {
         assert(PrimarySourceFiles.size() == 1);
         return *PrimarySourceFiles.begin();
      }
   }

   /// Returns true if there was an error during setup.
   bool setup(const CompilerInvocation &Invocation);

private:
   /// Set up the file system by loading and validating all VFS overlay YAML
   /// files. If the process of validating VFS files failed, or the overlay
   /// file system could not be initialized, this function returns true. Else it
   /// returns false if setup succeeded.
   bool setUpVirtualFileSystemOverlays();
   void setUpLLVMArguments();
   void setUpDiagnosticOptions();
   bool setUpModuleLoaders();
   bool isInputSwift() {
      return Invocation.getInputKind() == InputFileKind::PHP;
   }
   bool isInPILMode() {
      return Invocation.getInputKind() == InputFileKind::PIL;
   }

   bool setUpInputs();
   bool setUpAstContextIfNeeded();
   Optional<unsigned> setUpCodeCompletionBuffer();

   /// Set up all state in the CompilerInstance to process the given input file.
   /// Return true on error.
   bool setUpForInput(const InputFile &input);

   /// Find a buffer for a given input file and ensure it is recorded in
   /// SourceMgr, PartialModules, or InputSourceCodeBufferIDs as appropriate.
   /// Return the buffer ID if it is not already compiled, or None if so.
   /// Set failed on failure.

   Optional<unsigned> getRecordedBufferID(const InputFile &input, bool &failed);

   /// Given an input file, return a buffer to use for its contents,
   /// and a buffer for the corresponding module doc file if one exists.
   /// On failure, return a null pointer for the first element of the returned
   /// pair.
   Optional<ModuleBuffers> getInputBuffersIfPresent(const InputFile &input);

   /// Try to open the module doc file corresponding to the input parameter.
   /// Return None for error, nullptr if no such file exists, or the buffer if
   /// one was found.
   Optional<std::unique_ptr<llvm::MemoryBuffer>>
   openModuleDoc(const InputFile &input);

   /// Try to open the module source info file corresponding to the input parameter.
   /// Return None for error, nullptr if no such file exists, or the buffer if
   /// one was found.
   Optional<std::unique_ptr<llvm::MemoryBuffer>>
   openModuleSourceInfo(const InputFile &input);
public:
   /// Parses and type-checks all input files.
   void performSema();

   /// Parses the input file but does no type-checking or module imports.
   /// Note that this only supports parsing an invocation with a single file.
   void performParseOnly(bool EvaluateConditionals = false,
                         bool ParseDelayedBodyOnEnd = false);

   /// Parses and performs name binding on all input files.
   ///
   /// Like a parse-only invocation, a single file is required. Unlike a
   /// parse-only invocation, module imports will be processed.
   void performParseAndResolveImportsOnly();

   /// Performs mandatory, diagnostic, and optimization passes over the PIL.
   /// \param silModule The PIL module that was generated during PILGen.
   /// \param stats A stats reporter that will report optimization statistics.
   /// \returns true if any errors occurred.
   bool performPILProcessing(PILModule *silModule,
                             UnifiedStatsReporter *stats = nullptr);

private:
   SourceFile *
   createSourceFileForMainModule(SourceFileKind FileKind,
                                 SourceFile::ImplicitModuleImportKind ImportKind,
                                 Optional<unsigned> BufferID);

public:
   void freeAstContext();

   /// Frees up the PILModule that this instance is holding on to.
   void freePILModule();

private:
   /// Load stdlib & return true if should continue, i.e. no error
   bool loadStdlib();
   ModuleDecl *importUnderlyingModule();
   ModuleDecl *importBridgingHeader();

   void
   getImplicitlyImportedModules(SmallVectorImpl<ModuleDecl *> &importModules);

public: // for static functions in Frontend.cpp
   struct ImplicitImports {
      SourceFile::ImplicitModuleImportKind kind;
      ModuleDecl *objCModuleUnderlyingMixedFramework;
      ModuleDecl *headerModule;
      SmallVector<ModuleDecl *, 4> modules;

      explicit ImplicitImports(CompilerInstance &compiler);
   };

private:
   void createREPLFile(const ImplicitImports &implicitImports);

   void addMainFileToModule(const ImplicitImports &implicitImports);

   void performSemaUpTo(SourceFile::AstStageType LimitStage);
   void parseAndCheckTypesUpTo(const ImplicitImports &implicitImports,
                               SourceFile::AstStageType LimitStage);

   void parseLibraryFile(unsigned BufferID,
                         const ImplicitImports &implicitImports);

   /// Return true if had load error
   bool
   parsePartialModulesAndLibraryFiles(const ImplicitImports &implicitImports);

   void forEachFileToTypeCheck(llvm::function_ref<void(SourceFile &)> fn);

   void parseAndTypeCheckMainFileUpTo(SourceFile::AstStageType LimitStage);

   void finishTypeChecking();

public:
   const PrimarySpecificPaths &
   getPrimarySpecificPathsForWholeModuleOptimizationMode() const;
   const PrimarySpecificPaths &
   getPrimarySpecificPathsForPrimary(StringRef filename) const;
   const PrimarySpecificPaths &
   getPrimarySpecificPathsForAtMostOnePrimary() const;
   const PrimarySpecificPaths &
   getPrimarySpecificPathsForSourceFile(const SourceFile &SF) const;

   /// Write out the unparsed (delayed) source ranges
   /// Return true for error
   bool emitPHPRanges(DiagnosticEngine &diags, SourceFile *primaryFile,
                        StringRef outputPath) const;

   /// Return true for error
   bool emitCompiledSource(DiagnosticEngine &diags,
                           const SourceFile *primaryFile,
                           StringRef outputPath) const;
};

} // namespace polar

#endif // POLARPHP_FRONTEND_FRONTEND_H
